package ink.metoo.gude.module.security.controller

import ink.metoo.gude.aspect.RateLimit
import ink.metoo.gude.module.security.domain.SimpleUserDetails
import ink.metoo.gude.module.security.domain.dto.UpdateUserSettingDTO
import ink.metoo.gude.module.security.domain.vo.GetUserSettingVO
import ink.metoo.gude.module.security.domain.vo.UserDetailsVO
import ink.metoo.gude.module.security.service.UserService
import ink.metoo.gude.util.ApiUtils
import jakarta.validation.Valid
import jakarta.validation.constraints.NotNull
import org.springframework.http.MediaType
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile
import java.util.concurrent.TimeUnit

@RestController
@RequestMapping("/user")
class UserController(
    private val userService: UserService
) {

    @PreAuthorize("isAuthenticated()")
    @GetMapping("/details")
    fun getUserDetails(@AuthenticationPrincipal userDetails: SimpleUserDetails) =
        ApiUtils.success(UserDetailsVO(userDetails.user))

    @GetMapping("/fuzzy")
    fun fuzzySearch(@RequestParam @Valid @NotNull n: String) = ApiUtils.success(
        userService.fuzzySearch(n, 30)
            .map { UserDetailsVO(it) }
    )

    @PreAuthorize("isAuthenticated()")
    @GetMapping("/setting")
    fun getSetting(@AuthenticationPrincipal userDetails: SimpleUserDetails) =
        ApiUtils.success(GetUserSettingVO(userDetails.user))

    @PreAuthorize("isAuthenticated()")
    @PostMapping("/setting")
    fun updateSetting(
        @AuthenticationPrincipal userDetails: SimpleUserDetails,
        @RequestBody @Valid updateUserSetting: UpdateUserSettingDTO
    ) = ApiUtils.run {
        userService.updateSetting(userDetails.user, updateUserSetting)
    }

    @RateLimit(max = 5, duration = 1L, timeUnit = TimeUnit.DAYS, key = RateLimit.Key.USER)
    @PreAuthorize("isAuthenticated()")
    @PostMapping("/avatar/upload", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
    fun updateAvatar(
        @AuthenticationPrincipal userDetails: SimpleUserDetails,
        @RequestPart file: MultipartFile
    ) = ApiUtils.success(userService.uploadAvatar(userDetails.user, file))

}